package org.yun.seckill;

import com.google.common.util.concurrent.RateLimiter;
import org.springframework.dao.DuplicateKeyException;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;
import org.yun.biz.dao.OrderRepository;
import org.yun.biz.dao.StockRepository;
import org.yun.biz.model.Order;
import org.yun.constants.RedisConstant;
import org.yun.exception.BizException;
import org.yun.exception.ErrorCode;
import org.yun.util.*;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.util.Map;


/**
 * @ProjectName: no-concurrent
 * @ClassName: SimpleSeckill
 * @Description: 限流+mysql
 * @Author: liyunfeng31
 * @Date: 2020/10/4 23:22
 */
@SuppressWarnings("UnstableApiUsage")
@Component
public class SimpleStrategy implements SeckillStrategy {

    @Resource
    private RedisUtil redisUtil;

    @Resource
    private StockRepository stockDao;

    @Resource
    private OrderRepository orderDao;

    /**
     * 每秒不超过100个任务被提交
     */
    RateLimiter limiter = RateLimiter.create(100.0);


    @Transactional(rollbackFor = Exception.class)
    @Override
    public int secKill(Long userId, Long skuId, Long activityId, Integer num, String ip) {
        if(!limiter.tryAcquire()){ return 0; }
        Map<Object, Object> activity = redisUtil.hmget(RedisConstant.ACTIVITY_SKU + activityId + "_" + skuId);
        CommonUtil.checkActivity(activity,false);

        if(stockDao.decrStock(skuId, num) == 0){
            throw new BizException(ErrorCode.SEC_KILL.NO_STOCK);
        }

        Order order =  Order.initOrder(userId, skuId, activityId, BigDecimal.TEN);
        try {
            orderDao.save(order);
        }catch (DuplicateKeyException k){
            throw new BizException(ErrorCode.SEC_KILL.PARTICIPATED);
        }
        return 1;
    }
}
